<?php
/*
*  Класс обеспечивает работу с датами. Преобразование из формата, понятного человеку в формат БД и обратно
*/

//echo 'Date: ' . Service_Date::getCaseDateForUser('2008-05-16 08:59:20',3,1);
/**
 * Класс для работы с датой и временем
 *
 *Чаще всего используются 2 функции:
 * getTimeForUser возвращает дату и время во временном поясе пользователя, нужно передавать время из бд
 * gLocalTime2BD возвращает настоящее время по гринфичу, для записи в бд
 */
class Service_Date {

	/**
  * Возвращает время по гринфичу, для записи в бд
  *
  * @param unknown_type $localstamp
  * @return время по гринфичу
  */
 public static function gLocalTime2BD($localstamp = false) {
  if ($localstamp === false) $localstamp = time();
  return gmdate("Y-m-d H:i:s", $localstamp);
 }

  /**
   * возвращает только время
   */
  public static function getTimeOnly($date, $hour = true, $minute = true, $sec = true, $timeZone = 3){
  	$str = array();
  	if ($hour) $str[] = 'H';
  	if ($minute) $str[] = 'i';
  	if ($sec) $str[] = 's';
  	$str = join(':', $str);

  	if ($str){
	    $time = date($str, strtotime($date)+3600*Service_Date::summerTime($timeZone));
			return $time;
  	}
  	else
  		return 'ERROR';
  }

  /**
   * Функция возвращает дату и время в нужном падеже, по умолчанию родительном(падеж задается номером 1-именительный 2-родительный 3-дательном 4-винительный 5-творительный 6-предложный)
   *
   * @param str $date
   * @param int $timeZone
   * @param int $case
   * @return дату и время в нужном падеже
   */
  public static function getCaseDateForUser($date, $timeZone = 3, $case = 2, $strict = false, $noTimeFlag = false){
  	$convDate="";
  	$convTime="";
    $date = date('Y-m-d H:i:s', strtotime($date)+3600*Service_Date::summerTime($timeZone));
		$arrDate = getdate(strtotime($date));
		$convTime = substr($date,11, 5);
		$arrNow = /*getdate(time()-gmmktime(12)+mktime(12)+3600*Service_Date::summerTime($timeZone))*/getdate(time()+3600*Service_Date::summerTime($timeZone));

		switch ($case){
			case 1:
				$mothName = Service_Date::getMonthNameI($arrDate['mon']);
			break;
			case 2:
				$mothName = Service_Date::getMonthNameR($arrDate['mon']);
			break;
			case 3:
				$mothName = Service_Date::getMonthNameD($arrDate['mon']);
			break;
			case 4:
				$mothName = Service_Date::getMonthNameV($arrDate['mon']);
			break;
			case 5:
				$mothName = Service_Date::getMonthNameT($arrDate['mon']);
			break;
			case 6:
				$mothName = Service_Date::getMonthNameP($arrDate['mon']);
			break;
		}

		if ($arrNow['year'] == $arrDate['year'] and $arrNow['mon'] == $arrDate['mon']){
			if ($strict)
				$convDate = $arrDate['mday']." ".$mothName;
			else {
        switch ($arrNow['yday'] - $arrDate['yday']){
          case 0:
            $convDate = "Сегодня  ";
          break;
          /*case 1:
            $convDate = "Вчера  ";
          break;
          case 2:
            $convDate = "2 дня назад  ";
          break;
          case 3:
            $convDate = "3 дня назад  ";
          break;*/
          default:
            $convDate = $arrDate['mday']." ".$mothName;
          break;
        }
			}
		}
  	else {
  		$convDate = $arrDate['mday']." ".$mothName;
  	}

  	return $convDate . ($arrDate['year'] != $arrNow['year'] ? ' ' . $arrDate['year'] . ' г.' : '') . (($noTimeFlag OR $arrDate['year'] != $arrNow['year']) ? '' : ' в ' . $convTime);
  }

  public static function getNumDate($date, $timeZone = 3){
    $date = date('Y-m-d H:i:s', strtotime($date)+3600*Service_Date::summerTime($timeZone));
		$arrDate = getdate(strtotime($date));
		$convTime = substr($date,11, 5);
		$arrNow = getdate(time()+3600*Service_Date::summerTime($timeZone));
		$strReturn = date('d.m', strtotime($date)+3600*Service_Date::summerTime($timeZone));
		if ($arrDate['year'] != $arrNow['year'])
			$strReturn .= '.' . substr($arrDate['year'], 2,2);
		return $strReturn;
  }

  public static function getShortDateForUser($date, $timeZone = 3){
  	$convDate="";
  	$nDate = date('Y-m-d H:i:s', strtotime($date)+3600*Service_Date::summerTime($timeZone));
		$arrDate = getdate(strtotime($nDate));
		$arrNow = getdate(time()-gmmktime(12)+mktime(12)+3600*Service_Date::summerTime($timeZone));
		if (($arrNow['year'] == $arrDate['year']) && ($arrNow['mon'] == $arrDate['mon']) && ($arrNow['yday'] == $arrDate['yday']))
      $convDate = ($arrDate['hours'] < 10 ? '0' . $arrDate['hours'] : $arrDate['hours']) . ':' . ($arrDate['minutes'] < 10 ? '0' . $arrDate['minutes'] : $arrDate['minutes']);
  	else {
  		$convDate = ($arrDate['mday'] < 10 ? '0' . $arrDate['mday'] : $arrDate['mday']) . "." . ($arrDate['mon'] < 10 ? '0' . $arrDate['mon'] : $arrDate['mon']) . "." . date('y', strtotime($date)+3600*Service_Date::summerTime($timeZone));
  	}
  	return $convDate;
  }

  /**
   * Возвращает время временную зону ичитывая летнее и зимнее время
   *
   * @param int $timeZone
   * @return unknown
   */
	public static function summerTime($timeZone){
    //static $newTimeZone;
    if(!isset($newTimeZone)){
      $arrTime = localtime(time(),true);
      if ($arrTime['tm_isdst'] == 1)
        $newTimeZone = $timeZone + 1;
      else
        $newTimeZone = $timeZone;
    }
    return $newTimeZone;
  }


			//Функция возвращает название месяца в именительном падеже
	 public static function getMonthNameI($monthNumber, $superscript = false){
    switch ($monthNumber) {
    	case 1: return ($superscript ? "Я" : "я") . 'нварь';
    	case 2: return ($superscript ? "Ф" : "ф") . "евраль";
    	case 3: return ($superscript ? "М" : "м") . "арт";
    	case 4: return ($superscript ? "А" : "а") . "прель";
    	case 5: return ($superscript ? "М" : "м") . "ай";
    	case 6: return ($superscript ? "И" : "и") . "юнь";
    	case 7: return ($superscript ? "И" : "и") . "юль";
    	case 8: return ($superscript ? "А" : "а") . "вгуст";
    	case 9: return ($superscript ? "С" : "с") . "ентябрь";
    	case 10: return ($superscript ? "О" : "о") . "ктябрь";
    	case 11: return ($superscript ? "Н" : "н") . "оябрь";
    	case 12: return ($superscript ? "Д" : "д") . "екабрь";
    	default:return NULL;
    }
  }

  //Функция возвращает название месяца в радительном падеже
	public static function getMonthNameR($monthNumber){
    switch ($monthNumber) {
    	case 1: return "января";
    	case 2: return "февраля";
    	case 3: return "марта";
    	case 4: return "апреля";
    	case 5: return "мая";
    	case 6: return "июня";
    	case 7: return "июля";
    	case 8: return "августа";
    	case 9: return "сентября";
    	case 10: return "октября";
    	case 11: return "ноября";
    	case 12: return "декабря";
    	default:return NULL;
    }
  }
  //Функция возвращает название месяца в дательном падеже
	 public static function getMonthNameD($monthNumber){
    switch ($monthNumber) {
    	case 1: return "январь";
    	case 2: return "февраль";
    	case 3: return "март";
    	case 4: return "апрель";
    	case 5: return "май";
    	case 6: return "июнь";
    	case 7: return "июль";
    	case 8: return "август";
    	case 9: return "сентябрь";
    	case 10: return "октябрь";
    	case 11: return "ноябрь";
    	case 12: return "декабрь";
    	default:return NULL;
    }
  }
  //Функция возвращает название месяца в венительном падеже
	 public static function getMonthNameV($monthNumber){
    switch ($monthNumber) {
    	case 1: return "январь";
    	case 2: return "февраль";
    	case 3: return "март";
    	case 4: return "апрель";
    	case 5: return "май";
    	case 6: return "июнь";
    	case 7: return "июль";
    	case 8: return "август";
    	case 9: return "сентябрь";
    	case 10: return "октябрь";
    	case 11: return "ноябрь";
    	case 12: return "декабрь";
    	default:return NULL;
    }
  }
  //Функция возвращает название месяца в творительном падеже
	 public static function getMonthNameT($monthNumber){
    switch ($monthNumber) {
    	case 1: return "январь";
    	case 2: return "февраль";
    	case 3: return "март";
    	case 4: return "апрель";
    	case 5: return "май";
    	case 6: return "июнь";
    	case 7: return "июль";
    	case 8: return "август";
    	case 9: return "сентябрь";
    	case 10: return "октябрь";
    	case 11: return "ноябрь";
    	case 12: return "декабрь";
    	default:return NULL;
    }
  }
  //Функция возвращает название месяца в предложный падеже
	 public static function getMonthNameP($monthNumber){
    switch ($monthNumber) {
    	case 1: return "январь";
    	case 2: return "февраль";
    	case 3: return "март";
    	case 4: return "апрель";
    	case 5: return "май";
    	case 6: return "июнь";
    	case 7: return "июль";
    	case 8: return "август";
    	case 9: return "сентябрь";
    	case 10: return "октябрь";
    	case 11: return "ноябрь";
    	case 12: return "декабрь";
    	default:return NULL;
    }
  }
  /**
   * Преобразует дату, вводимую пользователем в формат Unix TimeStamp
   *
   * @param string $strDate
   * @return mixed - верет false, если дата указана некорректно
   */
  public static function humanDateToUnix($strDate) {
    $firstDot = strpos($strDate, '.');
    if (!$firstDot)//В строке нет точек
      return false;
    $secondDot = strpos($strDate, '.', $firstDot + 1);
    if (!$secondDot)//В строке всего одна точка
      return false;
    $day = intval(substr($strDate, 0, $firstDot));
    if (($day < 1) || ($day > 31))
      return false;
    $month = intval(substr($strDate, $firstDot + 1, $secondDot - $firstDot - 1));
    if (($month < 1) || ($month > 12))
      return false;
    $year = intval(substr($strDate, $secondDot + 1));
    if (($year < 1700) || ($year > 2100))
      return false;
    return
      mktime(0, 0, 0, $month, $day, $year);
  }

  /**
   * Проверка даты на правильность
   *
   * @param string $strDate
   * @return bool
   */
  public static function isDateCorrect($strDate) {
    return preg_match("/^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$/", $strDate);
  }

  /**
   * Проверка даты на правильность
   *
   * @param string $strDate
   * @return bool
   */
  public static function isDBDateCorrect($strDate) {
    return preg_match("/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/", $strDate);
  }

  /**
   * Преобразует дату, вводимую пользователем в формат, понятный БД
   *
   * @param string $strDate
   * @return mixed - верет false, если дата указана некорректно
   */
  public static function gHumanDateToBD($strDate) {
    $unixDate = self::humanDateToUnix($strDate);
    if (!$unixDate)
      return false;
    else
      return self::gLocalTime2BD($unixDate);
  }

   /**
   * Преобразует дату, вводимую пользователем в формат, понятный БД
   *
   * @param string $strDate
   * @return mixed - верет false, если дата указана некорректно
   */
  public static function HumanDateToBD($strDate) {
    $unixDate = strtotime($strDate);
    if(!$unixDate)
      return false;
    else
      return date("Y-m-d",$unixDate);
  }

   /**
   * получаем дату для фильтрации статей
   *
   * @param string $strDate
   * @return mixed - верет false, если дата указана некорректно
   * $plusOneDay - прибавляем один день, сделано для фильтрации статей
   */
  public static function filterDateBD($strDate, $plusOneDay = false) {
  	$unixDate = strtotime($strDate) + ($plusOneDay ?  86400 : 0);
    if(!$unixDate)
      return false;
    else
      return date("Y-m-d", $unixDate) . ' 00:00:00';
  }

  /**
   * Преобразует дату из формата БД в пользовательский
   *
   * @param string $strDate
   * @return mixed - вернет false, если дата указана некорректно
   */
  public static function BDDateToHuman($strDate) {
    $unixDate = strtotime($strDate);
    if(!$unixDate)
      return false;
    else
      return date("d.m.Y",$unixDate);
  }


  public static function addThreeMonthToDate($strDate) {
  	$arrDate = getdate(strtotime($strDate));
  	if ($arrDate['mon'] >= 10) $arrDate['year']++;
  	$arrDate['mon'] = ($arrDate['mon']+3) % 12;

  	return date('d.m.Y', mktime(0,0,0,$arrDate['mon'],$arrDate['mday'],$arrDate['year']));
  }

  public static function getDuration($seconds, $simplier, $superShort = false) {
  	$retText = '';
  	if($seconds < 60)
  	  return '0 минут';
  	$minutes = intval($seconds / 60);
  	if($minutes < 60)
  	  return $minutes . Service_Declension::getMinutesDeclension($minutes);
  	$hours = intval($minutes / 60);
  	$minutes = $minutes - $hours * 60;
  	if ($hours < 24) {
  	  if ($superShort)
  	    return $hours . 'ч ' . $minutes . 'м ';
  	  else
  	    return $hours . Service_Declension::getHoursDeclension($hours) . $minutes . Service_Declension::getMinutesDeclension($minutes);
  	}
  	$days = intval($hours / 24);
  	$hours = $hours - $days * 24;
  	if ($days < 30)
  	  if($simplier) {
  	    if ($superShort)
   	  	  return $days . 'д ' . $hours . 'ч';
   	  	else
   	  	  return $days . Service_Declension::getDaysDeclension($days) . $hours . Service_Declension::getHoursDeclension($hours);
  	  }
  	  else {
  	    if ($superShort)
  	      return $days . 'д ' . $hours . 'ч ' . $minutes . 'м';
  	    else
  	      return $days . Service_Declension::getDaysDeclension($days) . $hours . Service_Declension::getHoursDeclension($hours) . $minutes . Service_Declension::getMinutesDeclension($minutes);
  	  }
  	$months = intval($days / 30);
  	$days = $days - $months * 30;
	  if ($simplier) {
	  	if ($superShort)
	      return $months . 'мес ' . $days . 'дн';
	    else
        return $months . Service_Declension::getMonthsDeclension($months) . $days . Service_Declension::getDaysDeclension($days);
	  }
	  else
  	  if ($superShort)
  		  return $months . 'мес ' . $days . 'дн ' . $hours . 'ч ' . $minutes . 'м';
  		else
	  	  return $months . Service_Declension::getMonthsDeclension($months) . $days . Service_Declension::getDaysDeclension($days) . $hours . Service_Declension::getHoursDeclension($hours) . $minutes . Service_Declension::getMinutesDeclension($minutes);
  }

  public static function getQuestionExpireTimeLeft($creationDate, $answerTimeIndex, $superShort = true) {
		$secondsPassed = strtotime(date(self::gLocalTime2BD())) - strtotime(date($creationDate));
    $arrTimes = View_Question::$arrTimesBD; //время в с
    $leftPeriod = $arrTimes[$answerTimeIndex] - $secondsPassed;
		if ($leftPeriod < 0)
		  return false; //время истекло
		if ($leftPeriod > 3600)
		  return self::getDuration($leftPeriod, true, $superShort);
		else
		  return self::getDuration($leftPeriod, false, $superShort);
  }

  /**
   * Вычисляем, сколько времени осталось до граничного времени
   *
   * @param дата размещения $creationDate
   * @param всего времени выделено (в секундах) $secondsBorder
   * @param короткий ли вариант $superShort
   * @return unknown
   */
  public static function getSimpleTimeLeft($creationDate, $secondsBorder, $daysOnly = false) {
		$secondsPassed = strtotime(date(self::gLocalTime2BD())) - strtotime(date($creationDate));
    $leftPeriod = $secondsBorder - $secondsPassed;
		if ($leftPeriod < 0) return false; //время истекло
		if ($daysOnly) {
		  $dLeft = round($leftPeriod/(24*3600));
		  return $dLeft . Service_Declension::getDaysDeclension($dLeft);
		}
		else return self::getDuration($leftPeriod, false, true);
  }

  public static function getQuestionExpireStatus($creationDate, $answerTimeIndex) {
		$secondsPassed = strtotime(date(self::gLocalTime2BD())) - strtotime(date($creationDate));
    $arrTimes = View_Question::$arrTimesBD; //время в с
    $leftPeriod = $arrTimes[$answerTimeIndex] - $secondsPassed;
		if ($leftPeriod < 0)
		  return 0; //время истекло
		if ($leftPeriod <= 3600)
		  return 1; //совсем скоро истекает
		else
		  return 2; //время ещё есть
  }


  /**
   * Возвращает число или месяц двумя цифрами
   *
   * @param $number - число
   * @return число двумя цифрами
   */
  public static function twoDigits($number){
    if (strlen($number)<2) return '0' . $number;
    else return $number;
  }
  /**
   * Возвращает возраст
   *
   * @param string $birthDate
   * @return integer
   */
  public static function getAge($strBirthDate) {
  	$arrBirthDate = getdate(strtotime($strBirthDate));
  	$arrNowDate = getdate();
  	if($arrBirthDate['year'] >= $arrNowDate['year'])
  	  return 0;
  	if($arrBirthDate['mon'] < $arrNowDate['mon'] || ( ($arrBirthDate['mon'] == $arrNowDate['mon']) && ($arrBirthDate['mday'] <= $arrNowDate['mday']) ) )
  	  $age =  $arrNowDate['year'] - $arrBirthDate['year'];
  	else
  	  $age = $arrNowDate['year'] - $arrBirthDate['year'] - 1;

  	 $age =  strval($age);
  	 $last = $age{strlen($age)-1};
  	 switch ($last){
  	 	case 0: return $age . ' лет'; break;
  	 	case 1: return $age . ' год'; break;
  	 	case 2: return $age . ' года'; break;
  	 	case 3: return $age . ' года'; break;
  	 	case 4: return $age . ' года'; break;
  	 	case 5: return $age . ' лет'; break;
  	 	case 6: return $age . ' лет'; break;
  	 	case 7: return $age . ' лет'; break;
  	 	case 8: return $age . ' лет'; break;
  	 	case 9: return $age . ' лет'; break;
  	 }
  }

  /**
   * возварщает количесво дней пршедших с заданой даты в формате (hour, minute , second , month , day, year)
   */
  public static function getCountDayPast($hour, $minute , $second , $month , $day, $year){
  	return floor((time() - mktime($hour, $minute , $second , $month , $day, $year)) /86400);
  }

  /**
   * "красивый вывод даты"
   *
   */
  public static function getFullDate($date, $timeZone = 3){
    $date = date('Y-m-d H:i:s', strtotime($date)+3600*Service_Date::summerTime($timeZone));
		$arrDate = getdate(strtotime($date));
		return $arrDate['mday'] . ' ' . self::casemonth($arrDate['month']) . ' ' . $arrDate['year'] . ' года';
  }

  public static function caseWeekDay($weekday){
  	switch ($weekday){
  		case 'Monday': return 'Понедельник'; break;
  		case 'Tuesday': return 'Вторник'; break;
  		case 'Wednesday': return 'Среда'; break;
  		case 'Thursday': return 'Четверг'; break;
  		case 'Friday': return 'Пятница'; break;
  		case 'Saturday': return 'Суббота'; break;
  		case 'Sunday': return 'Воскресенье'; break;
  	}
  }

  public static function casemonth($month){
  	switch ($month){
  		case 'January': return 'января'; break;
  		case 'February': return 'февраля'; break;
  		case 'March': return 'марта'; break;
  		case 'April': return 'апреля'; break;
  		case 'May': return 'мая'; break;
  		case 'June': return 'июня'; break;
  		case 'July': return 'июля'; break;
  		case 'August': return 'августа'; break;
  		case 'September': return 'сентября'; break;
  		case 'October': return 'октября'; break;
  		case 'November': return 'ноября'; break;
  		case 'December': return 'декабря'; break;
  	}
  }
}
?>